import re
import sublime
import sublime_plugin
from .helper import ConstHelper


def is_chinese(uchar):
    if uchar >= 0x4e00 and uchar <= 0x9fa5:
        return True
    else:
        return False


class CalcRowWidthCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        sels = self.view.sel()
        if (len(sels) > 1):
            widths = []
            width = len(sels) + 1
            for sel in sels:
                line = self.view.substr(sel)
                width_t = 12
                for c in line:
                    if is_chinese(ord(c)):
                        width_t += 12
                    else:
                        width_t += 6
                widths.append(width_t)
                width += width_t
            print(width)
            print(widths)
        else:
            sel = sels[0]
            content = self.view.substr(sel)
            content = content.split('\n')
            content = content[2:len(content) - 1]
            width = len(content) + 1
            widths = []
            for line in content:
                line = line.split('"', 1)[1]
                line = line.rsplit('"', 1)[0]
                width_t = 12
                for c in line:
                    if is_chinese(ord(c)):
                        width_t += 12
                    else:
                        width_t += 6
                widths.append(width_t)
                width += width_t

            self.view.insert(edit, sel.end(), '\n' + str(widths))
            self.view.insert(edit, sel.end(), '\n' + str(width))


class ToUpperCaseCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        sels = self.view.sel()
        for sel in sels:
            selstr = self.view.substr(sel)
            self.view.replace(edit, sel, selstr.upper())


class ToLowerCaseCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        sels = self.view.sel()
        for sel in sels:
            selstr = self.view.substr(sel)
            self.view.replace(edit, sel, selstr.lower())


class HilightFunCodeAddrEventListener(sublime_plugin.EventListener):
    phantom_sets = {}
    phantoms = []

    __patterns = [
        r'^\s+LOGIC_ADD(.*)[\s\S]+(?=,[\s\S]+FUN_CODE[\s\S]+})',
        r'(?<=INT8U const gci8u_funCode\[\]\[3\] =\n)[\s\S]*?(?=};)',
        r'(?<=INT8U const gci8u_funCode\[\] =\n)[\s\S]*?(?=};)']

    def _search_text(self, view, pattern):
        text = view.substr(sublime.Region(0, view.size()))
        pattern = re.compile(pattern, re.MULTILINE)
        return pattern.search(text)

    def _get_area(self, view):
        result = self._search_text(view, self.__patterns[0])
        if result is None:
            return

        return sublime.Region(result.span()[0], result.span()[1])

    def _get_const_area(self, view):
        result = self._search_text(view, self.__patterns[1])
        if result is None:
            return

        return sublime.Region(result.span()[0] + 2, result.span()[1])

    def _get_const_area_with_pattern(self, view, pattern):
        result = self._search_text(view, pattern)
        if result is None:
            return

        return sublime.Region(result.span()[0] + 2, result.span()[1])

    def creat_phantoms(self, view, area):
        if area is None:
            return

        lines = view.lines(area)
        # print(lines)

        max_count = self.getNumCount(len(lines))
        # print(max_count)

        i = 0
        for line in lines:
            line_str = view.substr(line).strip()
            if line_str.find('//') == 0:
                continue

            if not line_str.strip():
                continue

            num_count = self.getNumCount(i)
            # print(num_count)
            space_str = '&nbsp;' * (max_count - num_count)
            # print(space_str)

            # print(line)
            content = '''
                <body>
                    <style type="text/css">
                        div.content {
                            background-color: #32AFF4;
                            border-radius: 4px;
                            color: #FFFFFF;
                            padding-left: 2px;
                            padding-right: 2px;
                        }
                    </style>
                    <div class="content">
                ''' + space_str + str(i) + '''
                        </div>
                    </body>
                '''

            phantom = sublime.Phantom(
                line,
                content,
                sublime.LAYOUT_INLINE)
            self.phantoms.append(phantom)
            i = i + 1

    def update_phantom_set(self, view):
        buffer_id = view.buffer_id()
        if buffer_id in self.phantom_sets:
            phantom_set = self.phantom_sets[buffer_id]
        else:
            phantom_set = sublime.PhantomSet(view, "Highligh")
            self.phantom_sets[buffer_id] = phantom_set

        phantom_set.update(self.phantoms)

    def update_view(self, view):
        view.erase_phantoms('Highligh')

        scope = view.scope_name(view.sel()[-1].b)
        if scope.find('source.c++') == -1:
            return

        self.phantoms = []
        self.creat_phantoms(view, self._get_area(view))
        self.creat_phantoms(view, self._get_const_area(view))
        self.creat_phantoms(
            view,
            self._get_const_area_with_pattern(view, self.__patterns[2])
        )
        self.update_phantom_set(view)

    def on_post_save(self, view):
        self.update_view(view)

    def on_activated(self, view):
        self.update_view(view)

    def getNumCount(sefl, num):
        return len(str(num))


class ConvertConstCommand(sublime_plugin.TextCommand):

    def _formInsertString(self, defDatas, minDatas, maxDatas):
        insertStr = '''
#define funCodeMax(x)       gci8u_funCode[x * 3 + 2]
#define funCodeDef(x)       gci8u_funCode[x * 3 + 1]
#define funCodeMin(x)       gci8u_funCode[x * 3 + 0]
INT8U const gci8u_funCode[] =
{
'''
        for i in range(0, len(defDatas)):
            insertStr += '    {' + minDatas[i] + ', ' + \
                defDatas[i] + ', ' + maxDatas[i] + '},\n'
        insertStr += '};\n'
        return insertStr

    def _convert(self, edit):
        defDatas = ConstHelper.getDatas(self.view, ConstHelper.defConstPattern)
        minDatas = ConstHelper.getDatas(self.view, ConstHelper.minConstPattern)
        maxDatas = ConstHelper.getDatas(self.view, ConstHelper.maxConstPattern)

        if (not defDatas) or (not minDatas) or (not maxDatas):
            return
        insertStr = self._formInsertString(defDatas, minDatas, maxDatas)
        sel = self.view.sel()[0]
        self.view.insert(edit, sel.end(), insertStr)

    def run(self, edit):
        self._convert(edit)


class ListConstsInputHandler(sublime_plugin.ListInputHandler):
    def list_items(self):
        return self.formDatas()

    def placeholder(self):
        return ''

    def confirm(self, value):
        pass

    def preview(self, value):
        if not self.addressList:
            return ''

        result = ConstHelper.getConstVariable(self.addressList[value][0])
        result += '<br>'
        result += self.constList[value][0]

        return sublime.Html(result)

    def formDatas(self):
        self.constList = ConstHelper.getConstList()
        self.addressList = ConstHelper.getAddressDatas()

        print(self.constList)
        print(self.addressList)

        if not self.constList or not self.addressList:
            return []

        if len(self.constList) != len(self.addressList):
            return [('数据长度不相等', 0)]

        datas = []
        for i in range(len(self.constList)):
            datas.append(
                ('%-2d' % (i) + self.addressList[i][0][:-4] +
                    '\t' + self.addressList[i][1], i))

        return datas

    def next_input(self, args):
        if not self.addressList or not self.constList:
            return

        index = args['list_consts']
        datas = {
            'addressName': self.addressList[index][0],
            'value': self.constList[index][0]
        }
        return ModificationOptionInputHandler(index, datas)


class AddressModifyInputHandler(sublime_plugin.TextInputHandler):
    def __init__(self, index, addressName):
        self.addressName = addressName

    def initial_text(self):
        return self.addressName


class ValueModifyInputHandler(sublime_plugin.TextInputHandler):
    def __init__(self, index, value):
        self.index = index
        self.value = value

    def initial_text(self):
        return self.value

    def confirm(self, text):
        data = text.split(',')
        for i in range(len(data)):
            data[i] = data[i].strip()
        ConstHelper.modifyData(data, self.index)


class ModificationOptionInputHandler(sublime_plugin.ListInputHandler):
    items = [
        ('Address', 0),
        ('Value', 1),
    ]

    def __init__(self, index, constDatas):
        self.index = index
        self.constDatas = constDatas
        self.inputList = [
            AddressModifyInputHandler(index, constDatas['addressName']),
            ValueModifyInputHandler(index, constDatas['value'])
        ]

    def list_items(self):
        return self.items

    def next_input(self, args):
        index = args['modification_option']
        return self.inputList[index]


class RemoveConstInputHandler(ListConstsInputHandler):
    def confirm(self, value):
        print('remove ' + str(value))
        ConstHelper.removeConst(value, self.addressList[value][0])


class ListConstsCommand(sublime_plugin.WindowCommand):
    def run(self, **args):
        pass

    def input(self, args):
        return ListConstsInputHandler()


class RemoveConstCommand(sublime_plugin.WindowCommand):
    def run(self, remove_const):
        pass

    def input(self, args):
        return RemoveConstInputHandler()
